﻿using Bussiness.DEV;
using Common;
using Model;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Bussiness
{
    public class TASIO : IDEV
    {
        public Device Device { get; set; }
        public List<DevicePOI> DevicePOIList { get; set; }
        private Socket SocketTAS;
        private byte[] ReceiveBuffer = new byte[4096];
        private int ReceiveLength = 0;

        public Result Connect()
        {
            Result result = new Result();
            IPAddress address;
            SocketTAS = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress.TryParse(Device.IP, out address);

            try
            {
                SocketTAS.Connect(address, Device.Port.Value);
                result.Success = true;
                result.Msg = "连接成功";

                new Thread(new ThreadStart(ReviceData))
                { IsBackground = true }.Start();
            }
            catch(Exception ex)
            {
                result.Msg = ex.StackTrace;
            }

            return result;
        }

        public Result<List<Cfg_Field>> Read()
        {
            Result<List<Cfg_Field>> result = new Result<List<Cfg_Field>>();
            byte[] buffer = BuildMessage(0x11,2, 0x20,8);

            try
            {
                SocketTAS.Send(buffer, SocketFlags.None);
                bool received = Wait();

                if (!received)
                {
                    result.Success = false;
                    result.Msg = "未收到回复数据";
                    return result;
                }

                if (!CRC.Check(ReceiveBuffer, ReceiveLength))
                {
                    result.Success = false;
                    result.Msg = "CRC16校验失败";
                    return result;
                }

                byte statusBtye = ReceiveBuffer[3];//8个通道状态字节
                foreach(var devPOI in DevicePOIList)
                {
                    Cfg_Field cfg_Field = new Cfg_Field();
                    cfg_Field.name = devPOI.DevPOIAlias;
                    bool hasIN = false;
                    switch (devPOI.Address)
                    {
                        case "1":
                            if ((statusBtye & 0x01) == 0x01)
                            {
                                hasIN = true;
                            }
                            break;
                        case "2":
                            if ((statusBtye & 0x02) == 0x02)
                            {
                                hasIN = true;
                            }
                            break;
                        case "3":
                            if ((statusBtye & 0x04) == 0x04)
                            {
                                hasIN = true;
                            }
                            break;
                        case "4":
                            if ((statusBtye & 0x08) == 0x08)
                            {
                                hasIN = true;
                            }
                            break;
                        case "5":
                            if ((statusBtye & 0x10) == 0x10)
                            {
                                hasIN = true;
                            }
                            break;
                        case "6":
                            if ((statusBtye & 0x20) == 0x20)
                            {
                                hasIN = true;
                            }
                            break;
                        case "7":
                            if ((statusBtye & 0x40) == 0x40)
                            {
                                hasIN = true;
                            }
                            break;
                        case "8":
                            if ((statusBtye & 0x80) == 0x80)
                            {
                                hasIN = true;
                            }
                            break;
                    }

                    cfg_Field.value = hasIN ? "1" : "0";
                    result.Data.Add(cfg_Field);
                }

                result.Success = true;
            }
            catch(Exception ex)
            {
                result.Msg = ex.ToString() + ex.StackTrace;
            }
            
            return result;
        }

        /// <summary>
        /// 判断是否收到回复
        /// </summary>
        /// <returns></returns>
        private bool Wait()
        {
            try
            {
                int waitTime = 0;
                while (waitTime < 1000)
                {
                    if (ReceiveBuffer[0] == 11  //设备地址
                        && ReceiveBuffer[1] == 0x02     //功能码
                        && ReceiveLength == 6)            //长度
                    {
                        return true;
                    }

                    if (ReceiveBuffer[1] == 0x83
                        || ReceiveBuffer[1] == 0x90)
                    {
                        return false;
                    }

                    Thread.Sleep(10);
                    waitTime += 10;
                }

                if (ReceiveLength == 0)
                {
                    return false;
                }

                return false;
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
                return false;
            }
        }

        /// <summary>
        /// 构造发送报文
        /// </summary>
        /// <param name="devAddr">设备地址</param>
        /// <param name="funcode">功能码</param>
        /// <param name="data">数据</param>
        /// <param name="addr">地址</param>
        /// <param name="count">变量个数</param>
        /// <returns></returns>
        private static byte[] BuildMessage(int devAddr, byte funCode, int addr, int count)
        {
            int crcVal;
            byte[] headData = new byte[6];
            headData[0] = Convert.ToByte(devAddr);//设备地址
            headData[1] = (byte)(funCode & 0xFF);//功能码 
            headData[2] = (byte)(addr >> 8);//寄存器地址第一个字节 >>8表示二进制向右移动8位，丢弃最右边的8位，并在最左边补上0
            headData[3] = (byte)(addr & 0xFF);//寄存器地址第二个字节
            headData[4] = (byte)(count >> 8);//寄存器个数第一个字节
            headData[5] = (byte)(count & 0xFF);//寄存器个数第二个字节
            byte[] messageData = new byte[headData.Length + 2];
            headData.CopyTo(messageData, 0);
            crcVal = CRC.Crc16(messageData, messageData.Length - 2);
            messageData[messageData.Length - 2] = (byte)(crcVal & 0xFF);//校验码第一个字节
            messageData[messageData.Length - 1] = (byte)(crcVal >> 8);//校验码第二个字节
            return messageData;
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        private void ReviceData()
        {
            while (true)
            {
                try
                {
                    ReceiveLength = SocketTAS.Receive(ReceiveBuffer, SocketFlags.None);
                }
                catch (Exception ex)
                {
                    LOG.Write(ex);
                    return;
                }
            }
        }
    }
}
